Passed
Push — master ( 3d6d98...867d13 )
by EMP
01:17
created

main.js ➔ displayOutMsg   A

Complexity

Conditions 3

Size

Total Lines 35
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 24
dl 0
loc 35
rs 9.304
c 0
b 0
f 0
1
"use strict";
2
3
sodium.ready.then(function() {
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
4
5
const ae = new AllEars(function(ok) {
1 ignored issue
show
Bug introduced by
The variable AllEars seems to be never declared. If this is a global, consider adding a /** global: AllEars */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6
	if (ok) {
7
		const greeting = localStorage.greeting;
1 ignored issue
show
Bug introduced by
The variable localStorage seems to be never declared. If this is a global, consider adding a /** global: localStorage */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
8
		if (greeting) {
9
			document.getElementById("greeting").textContent = greeting;
10
			document.getElementById("txt_pg").value = greeting;
11
		}
12
13
		document.getElementById("txt_skey").style.background = "#466";
14
		document.getElementById("txt_skey").maxLength = "64";
15
	} else {
16
		console.log("Failed to load All-Ears");
17
	}
18
});
19
20
function TabState(cur, max, btnDele, btnUpdt) {
21
	this.cur = cur;
22
	this.max = max;
23
	this.btnDele = btnDele;
24
	this.btnUpdt = btnUpdt;
25
}
26
27
const tabs = [
28
	new TabState(0, 0, false, true), // Inbox
29
	new TabState(0, 0, false, true), // Outbx
30
	new TabState(0, 2, true, false), // Write
31
	new TabState(0, 2, false, false), // Notes
32
	new TabState(0, 3, false, true) // Tools
33
];
34
35
let showHeaders = false;
36
37
let tab = 0;
38
const TAB_INBOX = 0;
39
const TAB_DRBOX = 1;
40
const TAB_WRITE = 2;
41
const TAB_NOTES = 3;
42
const TAB_TOOLS = 4;
43
44
// Helper functions
45
function getCountryName(countryCode) {
46
	switch (countryCode) {
47
		case "DZ": return "Africa/Algeria";
48
		case "AO": return "Africa/Angola";
49
		case "BJ": return "Africa/Benin";
50
		case "BW": return "Africa/Botswana";
51
		case "BF": return "Africa/Burkina Faso";
52
		case "BI": return "Africa/Burundi";
53
		case "CV": return "Africa/Cabo Verde";
54
		case "CM": return "Africa/Cameroon";
55
		case "CF": return "Africa/Central African Republic";
56
		case "TD": return "Africa/Chad";
57
		case "KM": return "Africa/Comoros";
58
		case "CD": return "Africa/Congo";
59
		case "DJ": return "Africa/Djibouti";
60
		case "EG": return "Africa/Egypt";
61
		case "GQ": return "Africa/Equatorial Guinea";
62
		case "ER": return "Africa/Eritrea";
63
		case "SZ": return "Africa/Eswatini";
64
		case "ET": return "Africa/Ethiopia";
65
		case "GA": return "Africa/Gabon";
66
		case "GM": return "Africa/Gambia";
67
		case "GH": return "Africa/Ghana";
68
		case "GW": return "Africa/Guinea-Bissau";
69
		case "GN": return "Africa/Guinea";
70
		case "CI": return "Africa/Ivory Coast";
71
		case "KE": return "Africa/Kenya";
72
		case "LS": return "Africa/Lesotho";
73
		case "LR": return "Africa/Liberia";
74
		case "LY": return "Africa/Libya";
75
		case "MG": return "Africa/Madagascar";
76
		case "MW": return "Africa/Malawi";
77
		case "ML": return "Africa/Mali";
78
		case "MR": return "Africa/Mauritania";
79
		case "MU": return "Africa/Mauritius";
80
		case "YT": return "Africa/Mayotte";
81
		case "MA": return "Africa/Morocco";
82
		case "MZ": return "Africa/Mozambique";
83
		case "NA": return "Africa/Namibia";
84
		case "NE": return "Africa/Niger";
85
		case "NG": return "Africa/Nigeria";
86
		case "CG": return "Africa/Republic of the Congo";
87
		case "RW": return "Africa/Rwanda";
88
		case "RE": return "Africa/Réunion";
89
		case "SH": return "Africa/Saint Helena";
90
		case "SN": return "Africa/Senegal";
91
		case "SC": return "Africa/Seychelles";
92
		case "SL": return "Africa/Sierra Leone";
93
		case "SO": return "Africa/Somalia";
94
		case "ZA": return "Africa/South Africa";
95
		case "SS": return "Africa/South Sudan";
96
		case "SD": return "Africa/Sudan";
97
		case "ST": return "Africa/São Tomé and Príncipe";
98
		case "TZ": return "Africa/Tanzania";
99
		case "TG": return "Africa/Togo";
100
		case "TN": return "Africa/Tunisia";
101
		case "UG": return "Africa/Uganda";
102
		case "EH": return "Africa/Western Sahara";
103
		case "ZM": return "Africa/Zambia";
104
		case "ZW": return "Africa/Zimbabwe";
105
		case "AQ": return "Antarctica/Antarctica";
106
		case "BV": return "Antarctica/Bouvet Island";
107
		case "TF": return "Antarctica/French Southern Territories";
108
		case "HM": return "Antarctica/Heard Island and McDonald Islands";
109
		case "GS": return "Antarctica/South Georgia and the South Sandwich Islands";
110
		case "AF": return "Asia/Afghanistan";
111
		case "AM": return "Asia/Armenia";
112
		case "AZ": return "Asia/Azerbaijan";
113
		case "BH": return "Asia/Bahrain";
114
		case "BD": return "Asia/Bangladesh";
115
		case "BT": return "Asia/Bhutan";
116
		case "IO": return "Asia/British Indian Ocean Territory";
117
		case "BN": return "Asia/Brunei";
118
		case "KH": return "Asia/Cambodia";
119
		case "CN": return "Asia/China";
120
		case "CC": return "Asia/Cocos [Keeling] Islands";
121
		case "GE": return "Asia/Georgia";
122
		case "JO": return "Asia/Hashemite Kingdom of Jordan";
123
		case "HK": return "Asia/Hong Kong";
124
		case "IN": return "Asia/India";
125
		case "ID": return "Asia/Indonesia";
126
		case "IR": return "Asia/Iran";
127
		case "IQ": return "Asia/Iraq";
128
		case "IL": return "Asia/Israel";
129
		case "JP": return "Asia/Japan";
130
		case "KZ": return "Asia/Kazakhstan";
131
		case "KW": return "Asia/Kuwait";
132
		case "KG": return "Asia/Kyrgyzstan";
133
		case "LA": return "Asia/Laos";
134
		case "LB": return "Asia/Lebanon";
135
		case "MO": return "Asia/Macao";
136
		case "MY": return "Asia/Malaysia";
137
		case "MV": return "Asia/Maldives";
138
		case "MN": return "Asia/Mongolia";
139
		case "MM": return "Asia/Myanmar";
140
		case "NP": return "Asia/Nepal";
141
		case "KP": return "Asia/North Korea";
142
		case "OM": return "Asia/Oman";
143
		case "PK": return "Asia/Pakistan";
144
		case "PS": return "Asia/Palestine";
145
		case "PH": return "Asia/Philippines";
146
		case "QA": return "Asia/Qatar";
147
		case "SA": return "Asia/Saudi Arabia";
148
		case "SG": return "Asia/Singapore";
149
		case "KR": return "Asia/South Korea";
150
		case "LK": return "Asia/Sri Lanka";
151
		case "SY": return "Asia/Syria";
152
		case "TW": return "Asia/Taiwan";
153
		case "TJ": return "Asia/Tajikistan";
154
		case "TH": return "Asia/Thailand";
155
		case "TR": return "Asia/Turkey";
156
		case "TM": return "Asia/Turkmenistan";
157
		case "AE": return "Asia/United Arab Emirates";
158
		case "UZ": return "Asia/Uzbekistan";
159
		case "VN": return "Asia/Vietnam";
160
		case "YE": return "Asia/Yemen";
161
		case "AL": return "Europe/Albania";
162
		case "AD": return "Europe/Andorra";
163
		case "AT": return "Europe/Austria";
164
		case "BY": return "Europe/Belarus";
165
		case "BE": return "Europe/Belgium";
166
		case "BA": return "Europe/Bosnia and Herzegovina";
167
		case "BG": return "Europe/Bulgaria";
168
		case "HR": return "Europe/Croatia";
169
		case "CY": return "Europe/Cyprus";
170
		case "CZ": return "Europe/Czechia";
171
		case "DK": return "Europe/Denmark";
172
		case "EE": return "Europe/Estonia";
173
		case "FO": return "Europe/Faroe Islands";
174
		case "FI": return "Europe/Finland";
175
		case "FR": return "Europe/France";
176
		case "DE": return "Europe/Germany";
177
		case "GI": return "Europe/Gibraltar";
178
		case "GR": return "Europe/Greece";
179
		case "GG": return "Europe/Guernsey";
180
		case "HU": return "Europe/Hungary";
181
		case "IS": return "Europe/Iceland";
182
		case "IE": return "Europe/Ireland";
183
		case "IM": return "Europe/Isle of Man";
184
		case "IT": return "Europe/Italy";
185
		case "JE": return "Europe/Jersey";
186
		case "XK": return "Europe/Kosovo";
187
		case "LV": return "Europe/Latvia";
188
		case "LI": return "Europe/Liechtenstein";
189
		case "LU": return "Europe/Luxembourg";
190
		case "MT": return "Europe/Malta";
191
		case "MC": return "Europe/Monaco";
192
		case "ME": return "Europe/Montenegro";
193
		case "NL": return "Europe/Netherlands";
194
		case "MK": return "Europe/North Macedonia";
195
		case "NO": return "Europe/Norway";
196
		case "PL": return "Europe/Poland";
197
		case "PT": return "Europe/Portugal";
198
		case "LT": return "Europe/Republic of Lithuania";
199
		case "MD": return "Europe/Republic of Moldova";
200
		case "RO": return "Europe/Romania";
201
		case "RU": return "Europe/Russia";
202
		case "SM": return "Europe/San Marino";
203
		case "RS": return "Europe/Serbia";
204
		case "SK": return "Europe/Slovakia";
205
		case "SI": return "Europe/Slovenia";
206
		case "ES": return "Europe/Spain";
207
		case "SJ": return "Europe/Svalbard and Jan Mayen";
208
		case "SE": return "Europe/Sweden";
209
		case "CH": return "Europe/Switzerland";
210
		case "UA": return "Europe/Ukraine";
211
		case "GB": return "Europe/United Kingdom";
212
		case "VA": return "Europe/Vatican City";
213
		case "AX": return "Europe/Åland";
214
		case "AI": return "North America/Anguilla";
215
		case "AG": return "North America/Antigua and Barbuda";
216
		case "AW": return "North America/Aruba";
217
		case "BS": return "North America/Bahamas";
218
		case "BB": return "North America/Barbados";
219
		case "BZ": return "North America/Belize";
220
		case "BM": return "North America/Bermuda";
221
		case "BQ": return "North America/Bonaire, Sint Eustatius, and Saba";
222
		case "VG": return "North America/British Virgin Islands";
223
		case "CA": return "North America/Canada";
224
		case "KY": return "North America/Cayman Islands";
225
		case "CR": return "North America/Costa Rica";
226
		case "CU": return "North America/Cuba";
227
		case "CW": return "North America/Curaçao";
228
		case "DM": return "North America/Dominica";
229
		case "DO": return "North America/Dominican Republic";
230
		case "SV": return "North America/El Salvador";
231
		case "GL": return "North America/Greenland";
232
		case "GD": return "North America/Grenada";
233
		case "GP": return "North America/Guadeloupe";
234
		case "GT": return "North America/Guatemala";
235
		case "HT": return "North America/Haiti";
236
		case "HN": return "North America/Honduras";
237
		case "JM": return "North America/Jamaica";
238
		case "MQ": return "North America/Martinique";
239
		case "MX": return "North America/Mexico";
240
		case "MS": return "North America/Montserrat";
241
		case "NI": return "North America/Nicaragua";
242
		case "PA": return "North America/Panama";
243
		case "PR": return "North America/Puerto Rico";
244
		case "BL": return "North America/Saint Barthélemy";
245
		case "LC": return "North America/Saint Lucia";
246
		case "MF": return "North America/Saint Martin";
247
		case "PM": return "North America/Saint Pierre and Miquelon";
248
		case "VC": return "North America/Saint Vincent and the Grenadines";
249
		case "SX": return "North America/Sint Maarten";
250
		case "KN": return "North America/St Kitts and Nevis";
251
		case "TT": return "North America/Trinidad and Tobago";
252
		case "TC": return "North America/Turks and Caicos Islands";
253
		case "VI": return "North America/U.S. Virgin Islands";
254
		case "US": return "North America/United States";
255
		case "AS": return "Oceania/American Samoa";
256
		case "AU": return "Oceania/Australia";
257
		case "CX": return "Oceania/Christmas Island";
258
		case "CK": return "Oceania/Cook Islands";
259
		case "TL": return "Oceania/Democratic Republic of Timor-Leste";
260
		case "FM": return "Oceania/Federated States of Micronesia";
261
		case "FJ": return "Oceania/Fiji";
262
		case "PF": return "Oceania/French Polynesia";
263
		case "GU": return "Oceania/Guam";
264
		case "KI": return "Oceania/Kiribati";
265
		case "MH": return "Oceania/Marshall Islands";
266
		case "NR": return "Oceania/Nauru";
267
		case "NC": return "Oceania/New Caledonia";
268
		case "NZ": return "Oceania/New Zealand";
269
		case "NU": return "Oceania/Niue";
270
		case "NF": return "Oceania/Norfolk Island";
271
		case "MP": return "Oceania/Northern Mariana Islands";
272
		case "PW": return "Oceania/Palau";
273
		case "PG": return "Oceania/Papua New Guinea";
274
		case "PN": return "Oceania/Pitcairn Islands";
275
		case "WS": return "Oceania/Samoa";
276
		case "SB": return "Oceania/Solomon Islands";
277
		case "TK": return "Oceania/Tokelau";
278
		case "TO": return "Oceania/Tonga";
279
		case "TV": return "Oceania/Tuvalu";
280
		case "UM": return "Oceania/U.S. Minor Outlying Islands";
281
		case "VU": return "Oceania/Vanuatu";
282
		case "WF": return "Oceania/Wallis and Futuna";
283
		case "AR": return "South America/Argentina";
284
		case "BO": return "South America/Bolivia";
285
		case "BR": return "South America/Brazil";
286
		case "CL": return "South America/Chile";
287
		case "CO": return "South America/Colombia";
288
		case "EC": return "South America/Ecuador";
289
		case "FK": return "South America/Falkland Islands";
290
		case "GF": return "South America/French Guiana";
291
		case "GY": return "South America/Guyana";
292
		case "PY": return "South America/Paraguay";
293
		case "PE": return "South America/Peru";
294
		case "SR": return "South America/Suriname";
295
		case "UY": return "South America/Uruguay";
296
		case "VE": return "South America/Venezuela";
297
	}
0 ignored issues
show
Comprehensibility introduced by
There is no default case in this switch, so nothing gets returned when all cases fail. You might want to consider adding a default or return undefined explicitly.
Loading history...
298
}
299
300
function getCountryFlag(countryCode) {
301
	return sodium.to_string(new Uint8Array([
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
302
		240, 159, 135, 166 + countryCode.codePointAt(0) - 65,
303
		240, 159, 135, 166 + countryCode.codePointAt(1) - 65
304
	]));
305
}
306
307
function getMsgId(num) {
308
	let i;
309
	if (ae.GetExtMsgHeaders(num).toLowerCase().slice(0, 11) === "message-id:") {
310
		i = 0;
311
	} else {
312
		i = ae.GetExtMsgHeaders(num).toLowerCase().indexOf("\nmessage-id:");
313
		if (i < 1) return "ERR";
314
		i++;
315
	}
316
317
	const x = ae.GetExtMsgHeaders(num).slice(i + 11).trim();
318
	if (x[0] !== "<") return "ERR2";
319
	return x.slice(1, x.indexOf(">"));
320
}
321
322
function clearDisplay() {
323
	let el = document.getElementById("midright").getElementsByTagName("img");
324
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("audio");
325
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("video");
326
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("embed");
327
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("iframe");
328
	if (el.length !== 1) return;
329
330
	URL.revokeObjectURL(el[0].src);
1 ignored issue
show
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
331
	el[0].remove();
332
}
333
334
function displayFile(num) {
335
	clearDisplay();
336
337
	document.getElementById("midright").scroll(0, 0);
338
	document.getElementById("midright").setAttribute("data-msgid", ae.GetUplMsgIdHex(num));
339
	document.getElementById("btn_reply").disabled = true;
340
	document.getElementById("btn_mdele").disabled = false;
341
	document.getElementById("midright").children[0].hidden = true;
342
	document.getElementById("midright").children[1].textContent = ae.GetUplMsgTitle(num);
343
344
	switch (ae.GetUplMsgType(num)) {
345
		case "text": {
346
			document.getElementById("midright").children[2].hidden = false;
347
			document.getElementById("midright").children[2].textContent = sodium.to_string(ae.GetUplMsgBody(num));
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
348
		break;}
349
350
		case "image": {
351
			document.getElementById("midright").children[2].hidden = true;
352
			const img = document.createElement("img");
353
			img.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
2 ignored issues
show
Bug introduced by
The variable Blob seems to be never declared. If this is a global, consider adding a /** global: Blob */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
354
			document.getElementById("midright").appendChild(img);
355
356
			img.onclick = function() {
357
				if (!document.fullscreen)
358
					img.requestFullscreen();
359
				else
360
					document.exitFullscreen();
361
			};
362
		break;}
363
364
		case "audio": {
365
			document.getElementById("midright").children[2].hidden = true;
366
			const el = document.createElement("audio");
367
			el.controls = "controls";
368
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
369
			document.getElementById("midright").appendChild(el);
370
		break;}
371
372
		case "video": {
373
			document.getElementById("midright").children[2].hidden = true;
374
			const el = document.createElement("video");
375
			el.controls = "controls";
376
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
377
			document.getElementById("midright").appendChild(el);
378
		break;}
379
380
		case "pdf": {
381
			document.getElementById("midright").children[2].hidden = true;
382
			const el = document.createElement("embed");
383
			el.type = "application/pdf";
384
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer], {type: "application/pdf"}));
385
			document.getElementById("midright").appendChild(el);
386
		break;}
387
388
		case "html": {
389
			document.getElementById("midright").children[2].hidden = true;
390
			const el = document.createElement("iframe");
391
			el.allow = "";
392
			el.sandbox = "";
393
			el.csp = "base-uri 'none'; child-src 'none'; connect-src 'none'; default-src 'none'; font-src 'none'; form-action 'none'; frame-ancestors 'none'; frame-src 'none'; img-src 'none'; manifest-src 'none'; media-src 'none'; object-src 'none'; script-src 'none'; style-src 'none'; worker-src 'none';";
394
			el.srcdoc = sodium.to_string(ae.GetUplMsgBody(num).buffer);
395
			document.getElementById("midright").appendChild(el);
396
		break;}
397
	}
398
}
399
400
function displayMsg(isInt, num) {
401
	clearDisplay();
402
403
	document.getElementById("btn_mdele").disabled = false;
404
	document.getElementById("midright").scroll(0, 0);
405
	document.getElementById("midright").setAttribute("data-msgid", isInt? ae.GetIntMsgIdHex(num) : ae.GetExtMsgIdHex(num));
406
407
	const ts = isInt? ae.GetIntMsgTime(num) : ae.GetExtMsgTime(num);
408
409
	document.getElementById("btn_reply").disabled = false;
410
	document.getElementById("btn_reply").onclick = function() {
411
		document.getElementById("write_recv").value = isInt? ae.GetIntMsgFrom(num) : ae.GetExtMsgFrom(num);
412
		document.getElementById("write_subj").value = "Re: " + (isInt ? ae.GetIntMsgTitle(num) : ae.GetExtMsgTitle(num));
413
		document.getElementById("write_rply").textContent = (isInt? "" : getMsgId(num));
414
		document.getElementById("btn_write").click();
415
		document.getElementById("div_write_1").hidden = false;
416
		document.getElementById("div_write_2").hidden = true;
417
		document.getElementById("write_body").focus();
418
		for (const opt of document.getElementById("write_from").options) {
419
			if (opt.value === (isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num))) {
420
				opt.selected = true;
421
			}
422
		}
423
	};
424
425
	document.getElementById("midright").children[0].hidden = false;
426
	document.getElementById("midright").children[2].hidden = false;
427
428
	if (isInt) {
429
		document.getElementById("midright").children[1].textContent = ae.GetIntMsgTitle(num);
430
		document.getElementById("midright").children[2].textContent = ae.GetIntMsgBody(num);
431
	} else {
432
		document.getElementById("midright").children[2].innerHTML = "";
433
434
		const headers = document.createElement("p");
435
		headers.textContent = ae.GetExtMsgHeaders(num);
436
		headers.className = "mono";
437
		headers.hidden = !showHeaders;
438
		document.getElementById("midright").children[2].appendChild(headers);
439
440
		const body = document.createElement("p");
441
		body.textContent = ae.GetExtMsgBody(num);
442
		document.getElementById("midright").children[2].appendChild(body);
443
444
		document.getElementById("midright").children[1].textContent = ae.GetExtMsgTitle(num);
445
		document.getElementById("midright").children[1].onclick = function() {showHeaders = !showHeaders; headers.hidden = !showHeaders;};
446
		document.getElementById("midright").children[1].style.cursor = "pointer";
447
	}
448
449
	document.getElementById("readmsg_envto").textContent = isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num);
450
451
	const tzOs = new Date().getTimezoneOffset();
452
	const tz = ((tzOs < 0) ? "+" : "-") + Math.floor(tzOs / -60).toString().padStart(2, "0") + (tzOs % 60 * -1).toString().padStart(2, "0");
453
	document.getElementById("readmsg_date").children[0].textContent = new Date((ts * 1000) + (tzOs * -60000)).toISOString().slice(0, 19).replace("T", " ") + " " + tz;
454
455
	if (!isInt) {
456
		document.getElementById("readmsg_ip").hidden = false;
457
		document.getElementById("readmsg_country").hidden = false;
458
		document.getElementById("readmsg_tls").hidden = false;
459
		document.getElementById("readmsg_greet").hidden = false;
460
461
		const cc = ae.GetExtMsgCountry(num);
462
463
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetExtMsgIp(num);
464
		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
465
		document.getElementById("readmsg_tls").children[0].textContent = ae.GetExtMsgTLS(num);
466
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetExtMsgGreet(num);
467
		document.getElementById("readmsg_envfrom").textContent = ae.GetExtMsgFrom(num);
468
469
		let flagText = "";
470
		if (!ae.GetExtMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
471
		if (!ae.GetExtMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
472
		if (!ae.GetExtMsgFlagPExt(num)) flagText += "<abbr title=\"The sender did not use the Extended (ESMTP) protocol\">SMTP</abbr> ";
473
		if (!ae.GetExtMsgFlagQuit(num)) flagText += "<abbr title=\"The sender did not issue the required QUIT command\">QUIT</abbr> ";
474
		if (ae.GetExtMsgFlagRare(num)) flagText += "<abbr title=\"The sender issued unusual command(s)\">RARE</abbr> ";
475
		if (ae.GetExtMsgFlagFail(num)) flagText += "<abbr title=\"The sender issued invalid command(s)\">FAIL</abbr> ";
476
		if (ae.GetExtMsgFlagPErr(num)) flagText += "<abbr title=\"The sender violated the protocol\">PROT</abbr> ";
477
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
478
	} else {
479
		document.getElementById("readmsg_ip").hidden = true;
480
		document.getElementById("readmsg_country").hidden = true;
481
		document.getElementById("readmsg_greet").hidden = true;
482
483
		document.getElementById("readmsg_tls").hidden = false;
484
		document.getElementById("readmsg_tls").textContent = ae.GetIntMsgFromPk(num);
485
486
		let symbol = "<span title=\"Invalid level\">&#x26a0;</span>";
487
		if (ae.GetIntMsgFrom(num) === "system") {if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"System\">&#x1f162;</span>";} // S (System)
488
		else if (ae.GetIntMsgLevel(num) === 0) symbol = "<span title=\"Level 0 User\">&#x1f10c;</span>"; // 0
489
		else if (ae.GetIntMsgLevel(num) === 1) symbol = "<span title=\"Level 1 User\">&#x278a;</span>"; // 1
490
		else if (ae.GetIntMsgLevel(num) === 2) symbol = "<span title=\"Level 2 User\">&#x278b;</span>"; // 2
491
		else if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"Administrator\">&#x1f150;</span>"; // A (Admin)
492
		document.getElementById("readmsg_envfrom").innerHTML = symbol + " " + ae.GetIntMsgFrom(num);
493
494
		let flagText = "";
495
		if (!ae.GetIntMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
496
		if (!ae.GetIntMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
497
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
498
	}
499
}
500
501
// Interface
502
function addMsg(isInt, i) {
503
	const row = document.getElementById("tbl_inbox").insertRow(-1);
504
	row.setAttribute("data-msgid", isInt? ae.GetIntMsgIdHex(i) : ae.GetExtMsgIdHex(i));
505
506
	const cellTime = row.insertCell(-1);
507
	const cellSubj = row.insertCell(-1);
508
	const cellSnd1 = row.insertCell(-1);
509
	const cellSnd2 = row.insertCell(-1);
510
511
	const ts = isInt? ae.GetIntMsgTime(i) : ae.GetExtMsgTime(i);
512
	cellTime.setAttribute("data-ts", ts);
513
	cellTime.textContent = new Date((ts * 1000) + (new Date().getTimezoneOffset() * -60000)).toISOString().slice(0, 10);
514
515
	cellSubj.textContent = isInt? ae.GetIntMsgTitle(i) : ae.GetExtMsgTitle(i);
516
517
	if (isInt) {
518
		cellSnd1.textContent = ae.GetIntMsgFrom(i);
519
		cellSnd1.className = (ae.GetIntMsgFrom(i).length === 16) ? "mono" : "";
520
	} else {
521
		const from1 = ae.GetExtMsgFrom(i);
522
		const from2 = from1.substring(from1.indexOf("@") + 1);
523
		const cc = ae.GetExtMsgCountry(i);
524
525
		cellSnd1.textContent = from1.substring(0, from1.indexOf("@"));
526
527
		const flag = document.createElement("abbr");
528
		flag.textContent = getCountryFlag(cc);
529
		flag.title = getCountryName(cc);
530
		cellSnd2.appendChild(flag);
531
532
		const fromText = document.createElement("span");
533
		fromText.textContent = " " + from2;
534
		cellSnd2.appendChild(fromText);
535
	}
536
537
	row.onclick = function() {
538
		displayMsg(isInt, i);
539
	};
540
}
541
542
function getRowsPerPage() {
543
	const tbl = document.getElementById("tbl_inbox");
544
	tbl.innerHTML = "";
545
	const row = tbl.insertRow(-1);
546
	const cell = row.insertCell(-1);
547
	cell.textContent = "0";
548
549
	const rowsPerPage = Math.floor(getComputedStyle(document.getElementById("div_inbox")).height.replace("px", "") / getComputedStyle(document.querySelector("#tbl_inbox > tbody > tr:first-child")).height.replace("px", "")) - 1; // -1 allows space for 'load more'
550
	tbl.innerHTML = "";
551
	return rowsPerPage;
552
}
553
554
function addMessages() {
555
	const rowsPerPage = getRowsPerPage();
556
	let skipMsgs = rowsPerPage * tabs[TAB_INBOX].cur;
557
558
	const maxExt = ae.GetExtMsgCount();
559
	const maxInt = ae.GetIntMsgCount();
560
561
	tabs[TAB_INBOX].max = Math.floor((maxExt + maxInt - 1) / rowsPerPage);
562
563
	let numExt = 0;
564
	let numInt = 0;
565
	let numAdd = 0;
566
567
	while (numAdd < rowsPerPage) {
568
		const tsInt = (numInt < maxInt) ? ae.GetIntMsgTime(numInt) : -1;
569
		const tsExt = (numExt < maxExt) ? ae.GetExtMsgTime(numExt) : -1;
570
		if (tsInt === -1 && tsExt === -1) break;
571
572
		if (tsInt !== -1 && (tsExt === -1 || tsInt > tsExt)) {
573
			if (skipMsgs > 0) skipMsgs--; else {addMsg(true, numInt); numAdd++;}
574
			numInt++;
575
		} else if (tsExt !== -1) {
576
			if (skipMsgs > 0) skipMsgs--; else {addMsg(false, numExt); numAdd++;}
577
			numExt++;
578
		}
579
	}
580
581
	if (ae.GetReadyMsgBytes() < ae.GetTotalMsgBytes()) {
582
		const inbox = document.getElementById("tbl_inbox");
583
		const row = inbox.insertRow(-1);
584
		const cell = row.insertCell(-1);
585
		cell.textContent = "Load more (" + (ae.GetTotalMsgBytes() - ae.GetReadyMsgBytes()) / 1024 + " KiB left)";
586
587
		row.onclick = function() {
588
			this.onclick = "";
589
590
			ae.Message_Browse(false, false, function(successBrowse) {
591
				document.getElementById("tbl_inbox").style.opacity = 1;
592
593
				if (successBrowse) {
594
					addMessages();
595
					addUploads();
596
					addSent();
597
					if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
598
				}
599
			});
600
		};
601
	}
602
}
603
604
function addUploads() {
605
	const tbl = document.getElementById("tbd_uploads");
606
	tbl.innerHTML = "";
607
608
	for (let i = 0; i < ae.GetUplMsgCount(); i++) {
609
		const row = tbl.insertRow(-1);
610
		row.setAttribute("data-msgid", ae.GetUplMsgIdHex(i));
611
612
		let cell;
613
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetUplMsgTime(i) * 1000).toISOString().slice(0, 10);
614
615
		cell = row.insertCell(-1); cell.textContent = ae.GetUplMsgTitle(i);
616
		cell.onclick = function() {displayFile(this.parentElement.rowIndex - 1);};
617
618
		cell = row.insertCell(-1); cell.textContent = (ae.GetUplMsgBytes(i) / 1024).toFixed(1);
619
620
		cell = row.insertCell(-1);
621
		if (ae.GetUplMsgIdHex(i)) {
622
			cell.innerHTML = "<button data-msgid=\"" + ae.GetUplMsgIdHex(i) + "\" type=\"button\">X</button>";
623
624
			cell.children[0].onclick = function() {
625
				const tr = this.parentElement.parentElement;
626
				ae.Message_Delete(this.getAttribute("data-msgid"), function(success) {
627
					if (success) tr.remove();
628
				});
629
			};
630
		}
631
	}
632
}
633
634
function displayOutMsg(num) {
635
	clearDisplay();
636
	document.getElementById("midright").scroll(0, 0);
637
	document.getElementById("midright").setAttribute("data-msgid", ae.GetOutMsgIdHex(num));
638
	document.getElementById("btn_reply").disabled = true;
639
	document.getElementById("btn_mdele").disabled = false;
640
	document.getElementById("midright").children[0].hidden = false;
641
	document.getElementById("midright").children[2].hidden = false;
642
643
	document.getElementById("midright").children[1].textContent = ae.GetOutMsgSubj(num);
644
	document.getElementById("midright").children[2].textContent = ae.GetOutMsgBody(num);
645
646
	document.getElementById("readmsg_envto").textContent = ae.GetOutMsgTo(num);
647
	document.getElementById("readmsg_envfrom").textContent = ae.GetOutMsgFrom(num);
648
649
	const ts = ae.GetOutMsgTime(num);
650
	const tzOs = new Date().getTimezoneOffset();
651
	const tz = ((tzOs < 0) ? "+" : "-") + Math.floor(tzOs / -60).toString().padStart(2, "0") + (tzOs % 60 * -1).toString().padStart(2, "0");
652
	document.getElementById("readmsg_date").children[0].textContent = new Date((ts * 1000) + (tzOs * -60000)).toISOString().slice(0, 19).replace("T", " ") + " " + tz;
653
654
	const isInt = ae.GetOutMsgIsInt(num);
655
	document.getElementById("readmsg_ip").hidden      = isInt;
656
	document.getElementById("readmsg_country").hidden = isInt;
657
	document.getElementById("readmsg_tls").hidden     = isInt;
658
	document.getElementById("readmsg_greet").hidden   = isInt;
659
660
	if (!isInt) {
661
//		const cc = ae.GetExtMsgCountry(num);
662
663
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetOutMsgIp(num);
664
//		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
665
//		document.getElementById("readmsg_tls").children[0].textContent = ae.GetOutMsgTLS(num);
666
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetOutMsgGreet(num);
667
	}
668
}
669
670
function addSent() {
671
	const tbl = document.getElementById("tbl_drbox");
672
	tbl.innerHTML = "";
673
674
	for (let i = 0; i < ae.GetOutMsgCount(); i++) {
675
		const row = tbl.insertRow(-1);
676
		row.setAttribute("data-msgid", ae.GetOutMsgIdHex(i));
677
678
		let cell;
679
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetOutMsgTime(i) * 1000).toISOString().slice(0, 10);
680
		cell = row.insertCell(-1); cell.textContent = ae.GetOutMsgSubj(i);
681
		row.onclick = function() {displayOutMsg(i);};
682
	}
683
}
684
685
function updateAddressCounts() {
686
	document.getElementById("limit_normal").textContent = (ae.GetAddressCountNormal() + "/" + ae.GetLimitNormalA(ae.GetUserLevel())).padStart(ae.GetLimitNormalA(ae.GetUserLevel()) > 9 ? 5 : 1);
687
	document.getElementById("limit_shield").textContent = (ae.GetAddressCountShield() + "/" + ae.GetLimitShieldA(ae.GetUserLevel())).padStart(ae.GetLimitShieldA(ae.GetUserLevel()) > 9 ? 5 : 1);
688
	document.getElementById("limit_total").textContent = ((ae.GetAddressCountNormal() + ae.GetAddressCountShield()) + "/" + ae.GetAddrPerUser()).padStart(5);
689
}
690
691
function adjustLevel(pubkey, level, c) {
692
	const fs = document.getElementById("fs_accs");
693
	fs.disabled = true;
694
695
	ae.Account_Update(pubkey, level, function(success) {
696
		fs.disabled = false;
697
698
		if (success) {
699
			c[4].textContent = level;
700
			c[5].children[0].disabled = (level === 3);
701
			c[6].children[0].disabled = (level === 0);
702
		}
703
	});
704
}
705
706
function addAccountToTable(i) {
707
	const tblAccs = document.getElementById("tbd_accs");
708
	const row = tblAccs.insertRow(-1);
709
	let cell;
710
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserPkHex(i);
711
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSpace(i);
712
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserNAddr(i);
713
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSAddr(i);
714
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserLevel(i);
715
716
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">+</button>";
717
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) + 1, c);};
718
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 3);
719
720
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">&minus;</button>";
721
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) - 1, c);};
722
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 0);
723
724
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">X</button>";
725
	cell.children[0].onclick = function() {
726
		const tr = this.parentElement.parentElement;
727
		ae.Account_Delete(tr.cells[0].textContent, function(success) {
728
			if (success) tr.remove();
729
		});
730
	};
731
}
732
733
function reloadAccount() {
734
	// Limits
735
	const tblLimits = document.getElementById("tbl_limits");
736
	if (ae.IsUserAdmin()) {
737
		for (let i = 0; i < 4; i++) {
738
			tblLimits.rows[i].cells[1].children[0].disabled = false;
739
			tblLimits.rows[i].cells[2].children[0].disabled = false;
740
			tblLimits.rows[i].cells[3].children[0].disabled = false;
741
742
			tblLimits.rows[i].cells[1].children[0].value = ae.GetLimitStorage(i) + 1;
743
			tblLimits.rows[i].cells[2].children[0].value = ae.GetLimitNormalA(i);
744
			tblLimits.rows[i].cells[3].children[0].value = ae.GetLimitShieldA(i);
745
		}
746
	} else {
747
		const lvl = ae.GetUserLevel();
748
		tblLimits.rows[lvl].cells[1].children[0].value = ae.GetLimitStorage(lvl) + 1;
749
		tblLimits.rows[lvl].cells[2].children[0].value = ae.GetLimitNormalA(lvl);
750
		tblLimits.rows[lvl].cells[3].children[0].value = ae.GetLimitShieldA(lvl);
751
	}
752
753
	// Accounts
754
	const tblAccs = document.getElementById("tbd_accs");
755
756
	// All: Our account
757
	const row = tblAccs.insertRow(-1);
758
	let cell;
759
	cell = row.insertCell(-1); cell.textContent = ae.GetUserPkHex();
760
	cell = row.insertCell(-1); cell.textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
761
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountNormal();
762
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountShield();
763
	cell = row.insertCell(-1); cell.textContent = ae.GetUserLevel();
764
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\" disabled=\"disabled\">+</button>";
765
766
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_downme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">&minus;</button>";
767
	cell.children[0].onclick = function() {
768
		const newLevel = parseInt(row.cells[4].textContent) - 1;
769
		ae.Account_Update(ae.GetUserPkHex(), newLevel, function(success) {
770
			if (success) row.cells[4].textContent = newLevel;
771
		});
772
	};
773
774
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_killme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">X</button>";
775
	cell.children[0].onclick = function() {
776
		ae.Account_Delete(ae.GetUserPkHex(), function(success) {
777
			if (success) row.remove();
778
		});
779
	};
780
781
	document.getElementById("txt_reg").disabled = !ae.IsUserAdmin();
782
	document.getElementById("btn_reg").disabled = !ae.IsUserAdmin();
783
784
	// Contacts
785
	for (let i = 0; i < ae.GetContactCount(); i++) {
786
		addContact(
787
			ae.GetContactMail(i),
788
			ae.GetContactName(i),
789
			ae.GetContactNote(i)
790
		);
791
	}
792
793
	// Addresses
794
	for (let i = 0; i < ae.GetAddressCount(); i++) {
795
		addAddress(i);
796
	}
797
798
	updateAddressCounts();
799
	addMessages();
800
	addUploads();
801
	addSent();
802
803
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
804
}
805
806
function deleteAddress(addr) {
807
	let btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
808
	for (let i = 0; i < btns.length; i++) btns[i].disabled = true;
809
810
	let addressToDelete = -1;
811
812
	for (let i = 0; i < ae.GetAddressCount(); i++) {
813
		if (addr === ae.GetAddress(i)) {
814
			addressToDelete = i;
815
			break;
816
		}
817
	}
818
819
	if (addressToDelete === -1) return;
820
821
	ae.Address_Delete(addressToDelete, function(success) {
822
		if (success) {
823
			document.getElementById("tbl_addrs").deleteRow(addressToDelete);
824
			document.getElementById("write_from").remove(addressToDelete);
825
			updateAddressCounts();
826
827
			if (ae.GetAddressCountNormal() < ae.GetLimitNormalA(ae.GetUserLevel())) document.getElementById("btn_address_create_normal").disabled = false;
828
			if (ae.GetAddressCountShield() < ae.GetLimitShieldA(ae.GetUserLevel())) document.getElementById("btn_address_create_shield").disabled = false;
829
830
			ae.Private_Update(function(success2) {
831
				if (!success2) console.log("Failed to update the Private field");
832
833
				btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
834
				for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
835
			});
836
		} else {
837
			console.log("Failed to delete address");
838
839
			btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
840
			for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
841
		}
842
	});
843
}
844
845 View Code Duplication
function shieldMix(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
846
	let newAddr = "";
847
848
	for (let i = 0; i < 16; i++) {
849
		switch (addr.charAt(i)) {
850
			case '1':
851
				newAddr += "1iIlL".charAt(Math.floor(Math.random() * 5));
852
				break;
853
			case '0':
854
				newAddr += "0oO".charAt(Math.floor(Math.random() * 3));
855
				break;
856
			case 'w':
857
				newAddr += "VvWw".charAt(Math.floor(Math.random() * 4));
858
				break;
859
			default:
860
				newAddr += (Math.random() > 0.5) ? addr.charAt(i) : addr.charAt(i).toUpperCase();
861
		}
862
	}
863
864
	return newAddr;
865
}
866
867
function addAddress(num) {
868
	const addrTable = document.getElementById("tbl_addrs");
869
	const row = addrTable.insertRow(-1);
870
	const cellAddr = row.insertCell(-1);
871
	const cellChk1 = row.insertCell(-1);
872
	const cellChk2 = row.insertCell(-1);
873
	const cellChk3 = row.insertCell(-1);
0 ignored issues
show
Unused Code introduced by
The constant cellChk3 seems to be never used. Consider removing it.
Loading history...
874
	const cellBtnD = row.insertCell(-1);
875
876
	cellAddr.textContent = ae.GetAddress(num);
877
	cellAddr.onclick = function() {
878
		if (cellAddr.textContent.length === 16)
879
			navigator.clipboard.writeText(shieldMix(cellAddr.textContent) + "@" + ae.GetDomainEml());
1 ignored issue
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
880
		else
881
			navigator.clipboard.writeText(cellAddr.textContent + "@" + ae.GetDomainEml());
882
	};
883
884
	cellChk1.innerHTML = ae.GetAddressAccExt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
885
	cellChk2.innerHTML = ae.GetAddressAccInt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
886
887
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
888
	cellBtnD.onclick = function() {deleteAddress(cellAddr.textContent);};
889
890
	const opt = document.createElement("option");
891
	opt.value = cellAddr.textContent;
892
	opt.textContent = cellAddr.textContent + "@" + ae.GetDomainEml();
893
	document.getElementById("write_from").appendChild(opt);
894
}
895
896
document.getElementById("btn_dele").onclick = function() {
897
	this.blur();
898
899
	if (tab === TAB_WRITE) {
900
		tabs[tab].cur = 0;
901
		updateTab();
902
903
		document.getElementById("write_recv").value = "";
904
		document.getElementById("write_subj").value = "";
905
		document.getElementById("write_body").value = "";
906
907
		document.getElementById("write_recv").focus();
908
	}
909
};
910
911
document.getElementById("btn_updt").onclick = function() {
912
	const btn = this;
913
	btn.disabled = true;
914
	btn.blur();
915
916
	if (tab === TAB_INBOX) {
917
		document.getElementById("tbl_inbox").style.opacity = 0.5;
918
919
		ae.Message_Browse(true, false, function(successBrowse) {
920
			document.getElementById("tbl_inbox").style.opacity = 1;
921
922
			if (successBrowse) {
923
				addMessages();
924
				addUploads();
925
				btn.disabled = false;
926
			} else {
927
				console.log("Failed to refresh");
928
				btn.disabled = false;
929
			}
930
		});
931
	}
932
};
933
934
document.getElementById("btn_mdele").onclick = function() {
935
	const btn = this;
936
	btn.blur();
937
	btn.disabled = true;
938
939
	const delId = document.getElementById("midright").getAttribute("data-msgid");
940
	if (!delId) return;
941
942
	ae.Message_Delete(delId, function(success) {
943
		if (success) {
944
			["tbl_inbox", "tbl_drbox", "tbd_uploads"].forEach(function(tbl_name) {
945
				const tbl = document.getElementById(tbl_name);
946
				for (let i = 0; i < tbl.rows.length; i++) {if (tbl.rows[i].getAttribute("data-msgid") === delId) tbl.deleteRow(i);}
947
			});
948
949
			addMessages();
950
			addUploads();
951
			addSent();
952
		} else btn.disabled = false;
953
	});
954
};
955
956
function addContact(mail, name, note) {
957
	const tbl = document.getElementById("tbl_ctact");
958
	const row = tbl.insertRow(-1);
959
	const cellMail = row.insertCell(-1);
960
	const cellName = row.insertCell(-1);
961
	const cellNote = row.insertCell(-1);
962
	const cellBtnD = row.insertCell(-1);
963
964
	cellMail.textContent = mail;
965
	cellName.textContent = name;
966
	cellNote.textContent = note;
967
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
968
969
	cellMail.contentEditable = true;
970
	cellName.contentEditable = true;
971
	cellNote.contentEditable = true;
972
973
	cellBtnD.onclick = function() {row.remove();};
974
}
975
976
document.getElementById("btn_newcontact").onclick = function() {
977
	addContact("", "", "");
978
};
979
980
document.getElementById("btn_savecontacts").onclick = function() {
981
	while (ae.GetContactCount() > 0) {
982
		ae.DeleteContact(0);
983
	}
984
985
	for (const row of document.getElementById("tbl_ctact").rows) {
986
		ae.AddContact(row.cells[0].textContent, row.cells[1].textContent, row.cells[2].textContent);
987
	}
988
989
	const btn = this;
990
	btn.disabled = true;
991
992
	ae.Private_Update(function(success) {
993
		btn.disabled = false;
994
995
		if (!success) {
996
			console.log("Failed contacts update");
997
		}
998
	});
999
};
1000
1001
function writeVerify() {
1002
	document.getElementById("div_write_1").hidden = true;
1003
	document.getElementById("div_write_2").hidden = false;
1004
1005
	document.getElementById("write2_recv").textContent = document.getElementById("write_recv").value;
1006
	document.getElementById("write2_subj").textContent = document.getElementById("write_subj").value;
1007
	document.getElementById("write2_rply").textContent = document.getElementById("write_rply").textContent;
1008
	document.getElementById("write2_body").textContent = document.getElementById("write_body").value;
1009
1010
	if (document.getElementById("write_recv").value.indexOf("@") >= 0) {
1011
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value + "@" + ae.GetDomainEml();
1012
		document.getElementById("write2_pkey").hidden = true;
1013
	} else {
1014
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value;
1015
		document.getElementById("write2_pkey").hidden = false;
1016
	}
1017
}
1018
1019
function updateTab() {
1020
	switch (tab) {
1021
		case TAB_INBOX:
1022
			addMessages();
1023
		break;
1024
1025
		case TAB_DRBOX:
1026
			addSent();
1027
		break;
1028
1029
		case TAB_WRITE:
1030
			switch (tabs[tab].cur) {
1031
				case 0: // Write
1032
					document.getElementById("div_write_1").hidden = false;
1033
					document.getElementById("div_write_2").hidden = true;
1034
					document.getElementById("write_body").focus();
1035
				break;
1036
1037
				case 1: // Verify
1038
					if (document.getElementById("write_recv").value.indexOf("@") >= 0) {
1039
						ae.Address_Lookup(document.getElementById("write_recv").value, function(pk) {
1040
							if (!pk) {
1041
								console.log("Failed lookup");
1042
								return;
1043
							}
1044
1045
							writeVerify();
1046
						});
1047
					} else writeVerify();
1048
				break;
1049
1050
				case 2: // Send
1051
					ae.Message_Create(
1052
						document.getElementById("write_subj").value,
1053
						document.getElementById("write_body").value,
1054
						document.getElementById("write_from").value,
1055
						document.getElementById("write_recv").value,
1056
						document.getElementById("write_rply").textContent,
1057
						(document.getElementById("write2_recv").textContent.indexOf("@") > 0) ? null : sodium.from_base64(document.querySelector("#write2_pkey > input").value, sodium.base64_variants.ORIGINAL_NO_PADDING),
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1058
						function(success) {
1059
							if (success) {
1060
								console.log("Sent ok");
1061
							} else {
1062
								console.log("Failed sending");
1063
							}
1064
						}
1065
					);
1066
				break;
1067
			}
1068
		break;
1069
1070
		case TAB_NOTES:
1071
			for (let i = 0; i <= tabs[tab].max; i++) {
1072
				document.getElementById("div_notes").children[i].hidden = (i !== tabs[tab].cur);
1073
			}
1074
		break;
1075
1076
		case TAB_TOOLS:
1077
			for (let i = 0; i <= tabs[tab].max; i++) {
1078
				document.getElementById("div_tools").children[i].hidden = (i !== tabs[tab].cur);
1079
			}
1080
		break;
1081
	}
1082
1083
	document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
1084
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
1085
}
1086
1087
document.getElementById("btn_left").onclick = function() {
1088
	tabs[tab].cur--;
1089
	if (tabs[tab].cur === 0) this.disabled = true;
1090
	if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
1091
	updateTab();
1092
	this.blur();
1093
};
1094
1095
document.getElementById("btn_rght").onclick = function() {
1096
	tabs[tab].cur++;
1097
	if (tabs[tab].cur === tabs[tab].max) this.disabled = true;
1098
	document.getElementById("btn_left").disabled = false;
1099
	updateTab();
1100
	this.blur();
1101
};
1102
1103
const buttons = document.querySelector("#main1 > .top").getElementsByTagName("button");
1104
for (let i = 0; i < buttons.length; i++) {
1105
	buttons[i].onclick = function() {
1106
		tab = i;
1107
1108
		for (let j = 0; j < buttons.length; j++) {
1109
			document.querySelector("#main1 > .mid").children[j].hidden = (tab !== j);
1110
			buttons[j].disabled = (tab === j);
1111
		}
1112
1113
		document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
0 ignored issues
show
Bug introduced by
The variable tab is changed as part of the for loop for example by i on line 1106. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
1114
		document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
1115
		document.getElementById("btn_dele").disabled = !tabs[tab].btnDele;
1116
		document.getElementById("btn_updt").disabled = !tabs[tab].btnUpdt;
1117
	};
1118
}
1119
1120
function addressCreate(addr) {
1121
	const btnN = document.getElementById("btn_address_create_normal");
1122
	const btnS = document.getElementById("btn_address_create_shield");
1123
	btnN.disabled = true;
1124
	btnS.disabled = true;
1125
1126
	ae.Address_Create(addr, function(success1) {
1127
		if (success1) {
1128
			ae.Private_Update(function(success2) {
1129
				addAddress(ae.GetAddressCount() - 1);
1130
				if (addr !== "SHIELD") document.getElementById("txt_address_create_normal").value = "";
1131
				updateAddressCounts();
1132
1133
				if (!success2) console.log("Failed to update the Private field");
1134
1135
				if (ae.GetAddressCountNormal() < ae.GetLimitNormalA(ae.GetUserLevel())) btnN.disabled = false;
1136
				if (ae.GetAddressCountShield() < ae.GetLimitShieldA(ae.GetUserLevel())) btnS.disabled = false;
1137
			});
1138
		} else {
1139
			console.log("Failed to add address");
1140
1141
			if (ae.GetAddressCountNormal() < ae.GetLimitNormalA(ae.GetUserLevel())) btnN.disabled = false;
1142
			if (ae.GetAddressCountShield() < ae.GetLimitShieldA(ae.GetUserLevel())) btnS.disabled = false;
1143
		}
1144
	});
1145
}
1146
1147
document.getElementById("btn_address_create_normal").onclick = function() {
1148
	if (ae.GetAddressCountNormal() >= ae.GetLimitNormalA(ae.GetUserLevel())) return;
1149
1150
	const txtNewAddr = document.getElementById("txt_address_create_normal");
1151
	if (!txtNewAddr.reportValidity()) return;
1152
1153
	addressCreate(txtNewAddr.value);
1154
};
1155
1156
document.getElementById("btn_address_create_shield").onclick = function() {
1157
	if (ae.GetAddressCountShield() >= ae.GetLimitShieldA(ae.GetUserLevel())) return;
1158
1159
	addressCreate("SHIELD");
1160
};
1161
1162
document.getElementById("btn_address_update").onclick = function() {
1163
	const btn = this;
1164
	btn.disabled = true;
1165
1166
	const rows = document.getElementById("tbl_addrs").rows;
1167
1168
	for (let i = 0; i < rows.length; i++) {
1169
		ae.SetAddressAccExt(i, rows[i].getElementsByTagName("input")[0].checked);
1170
		ae.SetAddressAccInt(i, rows[i].getElementsByTagName("input")[1].checked);
1171
	}
1172
1173
	ae.Address_Update(function(success) {
1174
		if (!success) console.log("Address/Update failed");
1175
		btn.disabled = false;
1176
	});
1177
};
1178
1179
document.getElementById("btn_reg").onclick = function() {
1180
	const btn = document.getElementById("btn_reg");
1181
	const txt = document.getElementById("txt_reg");
1182
	if (!txt.reportValidity()) return;
1183
	btn.disabled = true;
1184
1185
	ae.Account_Create(txt.value, function(success) {
1186
		if (success) {
1187
			addAccountToTable(ae.Admin_GetUserCount() - 1);
1188
			txt.value = "";
1189
		}
1190
1191
		btn.disabled = false;
1192
	});
1193
};
1194
1195
document.getElementById("chk_downme").onclick = function() {document.getElementById("btn_downme").disabled = !this.checked;};
1196
document.getElementById("chk_killme").onclick = function() {document.getElementById("btn_killme").disabled = !this.checked;};
1197
1198
document.getElementById("btn_notepad_saveupl").onclick = function() {
1199
	const np = document.getElementById("txt_notepad");
1200
	np.disabled = true;
1201
1202
	let fname = prompt("Save as...", "Untitled");
0 ignored issues
show
Debugging Code Best Practice introduced by
The prompt UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1203
	if (!fname.endsWith(".txt")) fname += ".txt";
1204
1205
	ae.Message_Upload(fname, np.value, function(success) {
1206
		if (success) {
1207
			np.value = "";
1208
			addUploads();
1209
			document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
1210
		}
1211
1212
		console.log("Failed to add text");
1213
		np.disabled = false;
1214
	});
1215
};
1216
1217
document.getElementById("btn_upload").onclick = function() {
1218
	const btn = this;
1219
	const fileSelector = document.createElement("input");
1220
	fileSelector.type = "file";
1221
	fileSelector.click();
1222
1223
	fileSelector.onchange = function() {
1224
		btn.disabled = true;
1225
1226
		const reader = new FileReader();
1 ignored issue
show
Bug introduced by
The variable FileReader seems to be never declared. If this is a global, consider adding a /** global: FileReader */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1227
		reader.onload = function() {
1228
			ae.Message_Upload(fileSelector.files[0].name, new Uint8Array(reader.result), function(success) {
1229
				if (success) {
1230
					addUploads();
1231
					document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
1232
				} else {
1233
					console.log("Failed upload");
1234
				}
1235
1236
				btn.disabled = false;
1237
			});
1238
		};
1239
1240
		reader.readAsArrayBuffer(fileSelector.files[0]);
1241
	};
1242
};
1243
1244
document.getElementById("btn_pg").onclick = function() {
1245
	localStorage.greeting = document.getElementById("txt_pg").value;
1 ignored issue
show
Bug introduced by
The variable localStorage seems to be never declared. If this is a global, consider adding a /** global: localStorage */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1246
};
1247
1248
document.getElementById("txt_skey").onkeyup = function(event) {
1249
	if (event.key === "Enter") {
1250
		event.preventDefault();
1251
		document.getElementById("btn_enter").click();
1252
	}
1253
};
1254
1255
document.getElementById("btn_enter").onclick = function() {
1256
	const txtSkey = document.getElementById("txt_skey");
1257
	if (!txtSkey.reportValidity()) return;
1258
1259
	const btn = this;
1260
	btn.disabled = true;
1261
	document.getElementById("txt_skey").style.background = "#233";
1262
1263
	ae.SetKeys(txtSkey.value, function(successSetKeys) {
1264
		if (successSetKeys) {
1265
			ae.Message_Browse(false, true, function(successBrowse) {
1266
				if (successBrowse) {
1267
					txtSkey.value = "";
1268
					document.getElementById("div_begin").hidden = true;
1269
					document.getElementById("div_main").style.display = "grid";
1270
					reloadAccount();
1271
1272
					if (ae.IsUserAdmin()) {
1273
						ae.Account_Browse(function(successAcc) {
1274
							if (successAcc) {for (let i = 0; i < ae.Admin_GetUserCount(); i++) {addAccountToTable(i);}}
1275
							else console.log("Failed to Account_Browse");
1276
						});
1277
					}
1278
				} else {
1279
					console.log("Failed to enter");
1280
					btn.disabled = false;
1281
					document.getElementById("txt_skey").style.background = "#466";
1282
					txtSkey.focus();
1283
				}
1284
			});
1285
		} else {
1286
			console.log("Invalid format for key");
1287
			btn.disabled = false;
1288
			document.getElementById("txt_skey").style.background = "#466";
1289
			txtSkey.focus();
1290
		}
1291
	});
1292
};
1293
1294
});
1295